<?php

namespace app\logic;

use app\Api;
use think\Cache;

class WeChat extends Api
{
    private static $obj = null;

    private $dir;

    public function _initialize()
    {
        parent::_initialize();
        $this->dir = dirname(dirname(__FILE__));
    }

    /**
     * 类入口
     * @return WeChat|null
     */
    public static function getInstance()
    {
        if (is_null(self::$obj))
            self::$obj = new self();
        return self::$obj;
    }

    /**
     * 获取JsApi
     * @return bool
     */
    public function getJsApi()
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $this->getAccessToken() . '&type=jsapi&offset_type=1';
        $res = json_decode($this->_curlGet($url), true);
        if ($res['errcode'] == 0) {
            return $res['ticket'];
        }
        return false;
    }

    /**
     * 获取access_token
     * @return mixed|string
     */
    public function getAccessToken($bool_status = true)
    {
        if ($bool_status === false) {
            $str_access_token = Cache::get('yxm_access_token_201801122');
            if (isset($str_access_token) && strlen($str_access_token) > 0) {
                return $str_access_token;
            }
        }

        $arr_info = (array)json_decode($this->_curlGet('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . config('wechat.public_number_app_id') . '&secret=' . config('wechat.public_number_app_secret')), true);
        if (isset($arr_info['access_token'])) {
            Cache::rm('yxm_access_token_201801122');
            Cache::set('yxm_access_token_201801122', $arr_info['access_token'], 7000);
            return $arr_info['access_token'];
        }

        Cache::rm('yxm_access_token_201801122');
        return '';
    }

    /**
     * 获取用户二维码（推广码）
     * @param $str_openid
     * @return string
     */
    public function getQrCode($str_openid)
    {
        $str_qrcode_url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?";
        $str_qrcode_get_url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?";
        $str_scene = 'yxm-hb-|' . $str_openid;

        $url = $str_qrcode_url . 'access_token=' . $this->getAccessToken();
        $qrcode = '{"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "' . $str_scene . '"}}}';
        $arr_result = json_decode($this->_curlPost($url, $qrcode), true);
        if (isset($arr_result['ticket'])) {
            return $str_qrcode_get_url . 'ticket=' . $arr_result['ticket'];
        }

        $url = $str_qrcode_url . 'access_token=' . $this->getAccessToken(true);
        $arr_result = json_decode($this->_curlPost($url, $qrcode), true);
        if (isset($arr_result['ticket'])) {
            return $str_qrcode_get_url . 'ticket=' . $arr_result['ticket'];
        }

        return '';
    }

    /**
     * 根据code获取用户的openid
     * @param $str_code
     * @return array|bool
     */
    public function getUserOpenid($str_code)
    {
        $str_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . config('wechat.public_number_app_id') . '&secret=' . config('wechat.public_number_app_secret') . '&code=' . $str_code . '&grant_type=authorization_code';
        $arr_data = (array)json_decode($this->_curlGet($str_url), true);
        if (isset($arr_data['openid'])) {
            return ['openid' => strval($arr_data['openid']), 'access_token' => $arr_data['access_token']];
        }
        return false;
    }

    /**
     * 根据code获取用户的openid
     * @param $str_code
     * @return array|bool
     */
    public function getAppOpenid($str_code)
    {
        $str_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . config('wechat.app_app_id') . '&secret=' . config('wechat.app_app_secret') . '&code=' . $str_code . '&grant_type=authorization_code';
        $arr_data = (array)json_decode($this->_curlGet($str_url), true);
        if (isset($arr_data['openid'])) {
            return ['openid' => strval($arr_data['openid']), 'access_token' => $arr_data['access_token']];
        }
        return false;
    }

    /**
     * 获取用户基本信息(UnionID机制)
     * @return array|bool
     *
     */
    public function getUserInfo($str_openid, $str_access_token)
    {
        $str_url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $this->getAccessToken() . '&openid=' . $str_openid . '&lang=zh_CN';
        $arr_info = (array)json_decode($this->_curlGet($str_url), true);
        if (isset($arr_info['subscribe']) && isset($arr_info['openid'])) {
            if ($arr_info['subscribe'] != 1) {
                return $this->getWechatUserInfo($str_access_token, $str_openid);
            }
            return [
                'openid' => $arr_info['openid'],
                'nickname' => $arr_info['nickname'],
                'sex' => $arr_info['sex'],
                'city' => $arr_info['city'],
                'province' => $arr_info['province'],
                'country' => $arr_info['country'],
                'headimgurl' => $arr_info['headimgurl'],
                'unionid' => isset($arr_info['unionid']) ? $arr_info['unionid'] : '',
            ];
        }
        return false;
    }

    public function getWechatUserInfo($str_access_token, $str_openid)
    {
        $str_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $str_access_token . '&openid=' . $str_openid . '&lang=zh_CN';
        $arr_info = (array)json_decode($this->_curlGet($str_url), true);
        if (isset($arr_info['openid']) && isset($arr_info['nickname'])) {
            return [
                'openid' => $arr_info['openid'],
                'nickname' => $arr_info['nickname'],
                'sex' => $arr_info['sex'],
                'city' => $arr_info['city'],
                'province' => $arr_info['province'],
                'country' => $arr_info['country'],
                'headimgurl' => $arr_info['headimgurl'],
                'unionid' => isset($arr_info['unionid']) ? $arr_info['unionid'] : '',
            ];
        }
        return false;
    }

    /**
     * 生成签名信息
     * @param array $data
     * @return array
     */
    public function weChatSign($data, $str_key)
    {
        ksort($data);

        $sign = '';
        $xml = '<xml>';
        foreach ($data as $key => $value) {
            if (empty($value) === false) {
                $sign .= $key . '=' . $value . '&';
                $xml .= '<' . $key . '><![CDATA[' . $value . ']]></' . $key . '>';
            }
        }
        unset($key, $value);

        $sign .= 'key=' . $str_key;

        $sign = strtoupper(md5($sign));

        $xml .= '<' . 'sign><![CDATA[' . $sign . ']]></sign></xml>';

        return ['sign' => $sign, 'xml' => $xml];
    }

    /**
     * 微信 ssl Curl Post数据
     * @param string $str_type 类型 public_number-公众号、app-开放平台应用
     * @param string $url 接收数据的api
     * @param string $vars 提交的数据
     * @param int $second 要求程序必须在$second秒内完成,负责到$second秒后放到后台执行
     * @param array $aHeader 请求头内容
     * @return int|mixed 成功且对方有返回值则返回
     */
    public function curlPostSsl($str_type, $str_url, $str_vars, $int_second = 30, $arr_header = array('Expect:'))
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, $int_second);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $str_url);

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);   // 只信任CA颁布的证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名，并且是否与提供的主机名匹配
        curl_setopt($ch, CURLOPT_CAINFO, $this->dir . config('wechat.' . $str_type . '_ca_pem')); // CA根证书（用来验证的网站证书是否是CA颁布）
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT, $this->dir . config('wechat.' . $str_type . '_cert_pem'));
        curl_setopt($ch, CURLOPT_SSLCERTPASSWD, config('wechat.' . $str_type . '_mch_id'));
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, $this->dir . config('wechat.' . $str_type . '_key_pem'));

        if (count($arr_header) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $arr_header);
        }

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $str_vars);
        $data = curl_exec($ch);
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            return $error;
        }
    }
}
